/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package TimeRecording.tables;

import TimeRecording.enums.AuthorisationLevel;
import TimeRecording.enums.EmployeeStatus;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.io.Serializable;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import javax.persistence.Basic;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EntityManager;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;
import javax.persistence.Query;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.Transient;

/**
 *
 * @author dpatchett
 */
@Entity
@Table(name = "employee")
@NamedQueries({
    @NamedQuery(name = "Employee.findAll",
            query = "SELECT e " +
                    "FROM Employee e " +
                    "ORDER BY e.surname, e.forename"),
    @NamedQuery(name = "Employee.findByEmployeeId",
            query = "SELECT e " +
                    "FROM Employee e " +
                    "WHERE e.employeeId = :employeeId"),
    @NamedQuery(name = "Employee.findByPayrollReference",
            query = "SELECT e " +
                    "FROM Employee e " +
                    "WHERE e.payrollReference = :payrollReference"),
    @NamedQuery(name = "Employee.findByUsername",
            query = "SELECT e " +
                    "FROM Employee e " +
                    "WHERE e.username = :username"),
    @NamedQuery(name = "Employee.findByAuthorisationLevel",
            query = "SELECT e " +
                    "FROM Employee e " +
                    "WHERE e.authorisationLevel = :authorisationLevel " +
                    "ORDER BY e.surname, e.forename"),
    @NamedQuery(name = "Employee.findByNotAuthorisationLevel",
            query = "SELECT e " +
                    "FROM Employee e " +
                    "WHERE e.authorisationLevel <> :authorisationLevel " +
                    "ORDER BY e.surname, e.forename")})

public class Employee implements Serializable {

    @Transient
    private PropertyChangeSupport changeSupport = new PropertyChangeSupport(this);
    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Basic(optional = false)
    @Column(name = "employee_id")
    private Integer employeeId;

    @Column(name = "forename")
    private String forename;

    @Column(name = "surname")
    private String surname;

    @Basic(optional = false)
    @Column(name = "status_time")
    @Temporal(TemporalType.TIMESTAMP)
    private Date statusTime;

    @Column(name = "payroll_reference")
    private String payrollReference;

    @Column(name = "username")
    private String username;

    @Column(name = "password")
    private String password;

    @Column(name = "sickness")
    private double sickness;

    @OneToOne(cascade = CascadeType.ALL, mappedBy = "employees")
    private WorkingSummary workingPatternsMaster;

    @OneToMany(cascade = CascadeType.ALL, mappedBy = "employees")
    private List<WorkingPattern> workingPatterns;

    @OneToMany(mappedBy = "employeeId")
    private Collection<Event> eventsLogCollection;

    @OneToMany(mappedBy = "acknowledgedById")
    private Collection<Event> eventsLogCollection1;

    @Column(name = "status")
    private EmployeeStatus status;

    @Column(name = "authorisation_level")
    private AuthorisationLevel authorisationLevel;

    @OneToMany(mappedBy = "employeeId")
    private Collection<Badge> badges;

    @OneToMany(cascade = CascadeType.ALL, mappedBy = "employeeId")
    private Collection<HolidayRequest> holidayRequests;

    @OneToMany(cascade = CascadeType.ALL, mappedBy = "employeeId")
    private Collection<HolidayAdjustment> holidayAdjustments;

    @OneToMany(cascade = CascadeType.ALL, mappedBy = "employeeId")
    private Collection<SicknessReport> sicknessReports;

    @OneToMany(cascade = CascadeType.ALL, mappedBy = "employee")
    private Collection<WeeklyTime> weeklyTimes;

    @OneToMany(cascade = CascadeType.ALL, mappedBy = "employee")
    private Collection<MonthlyTime> monthlyTimes;

    @OneToMany(cascade = CascadeType.ALL, mappedBy = "employeeId")
    private Collection<ClockedPeriod> clockedPeriods;

    @OneToMany(cascade = CascadeType.ALL, mappedBy = "employeeId")
    private Collection<Session> sessions;

    @Transient
    private String friendlyName;
    
    public Employee() {
        authorisationLevel = AuthorisationLevel.EMPLOYEE;
        status = EmployeeStatus.CLOCKED_OUT;
    }

    public Employee(Integer employeeId) {
        this();
        this.employeeId = employeeId;
    }

    public Employee(Integer employeeId, Date statusTime) {
        this.employeeId = employeeId;
        this.statusTime = statusTime;
    }

    public Integer getEmployeeId() {
        return employeeId;
    }

    public void setEmployeeId(Integer employeeId) {
        Integer oldEmployeeId = this.employeeId;
        this.employeeId = employeeId;
        changeSupport.firePropertyChange("employeeId", oldEmployeeId, employeeId);
        setFriendlyName("dummy");
    }

    public String getForename() {
        return forename;
    }

    public void setForename(String forename) {
        String oldForename = this.forename;
        this.forename = forename;
        changeSupport.firePropertyChange("forename", oldForename, forename);
        setFriendlyName("dummy");
    }

    public String getSurname() {
        return surname;
    }

    public void setSurname(String surname) {
        String oldSurname = this.surname;
        this.surname = surname;
        changeSupport.firePropertyChange("surname", oldSurname, surname);
        setFriendlyName("dummy");
    }

    public Date getStatusTime() {
        return statusTime;
    }

    public void setStatusTime(Date statusTime) {
        Date oldStatusTime = this.statusTime;
        this.statusTime = statusTime;
        changeSupport.firePropertyChange("statusTime", oldStatusTime, statusTime);
    }

    public String getPayrollReference() {
        return payrollReference;
    }

    public void setPayrollReference(String payrollReference) {
        String oldPayrollReference = this.payrollReference;
        this.payrollReference = payrollReference;
        changeSupport.firePropertyChange("payrollReference", oldPayrollReference, payrollReference);

    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        String oldUsername = this.username;
        this.username = username;
        changeSupport.firePropertyChange("username", oldUsername, username);
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        String oldPassword = this.password;
        this.password = password;
        changeSupport.firePropertyChange("password", oldPassword, password);
    }

    public double getSickness() {
        return sickness;
    }

    public void setSickness(double sickness) {
        double oldSickness = this.sickness;
        this.sickness = sickness;
        changeSupport.firePropertyChange("sickness", oldSickness, sickness);
    }

    public WorkingSummary getWorkingPatternsMaster() {
        return workingPatternsMaster;
    }

    public void setWorkingPatterns(WorkingSummary workingPatternsMaster) {
        WorkingSummary oldWorkingPatternsMaster = this.workingPatternsMaster;
        this.workingPatternsMaster = workingPatternsMaster;
        changeSupport.firePropertyChange("workingPatternsMaster", oldWorkingPatternsMaster, workingPatternsMaster);
    }

//    public EmployeeHolidays getEmployeeHolidays() {
//        return employeeHolidays;
//    }
//
//    public void setEmployeeHolidays(EmployeeHolidays employeeHolidays) {
//        EmployeeHolidays oldEmployeeHolidays = this.employeeHolidays;
//        this.employeeHolidays = employeeHolidays;
//        changeSupport.firePropertyChange("employeeHolidays", oldEmployeeHolidays, employeeHolidays);
//    }
//
//    public EmployeeSickness getEmployeeSickness() {
//        return employeeSickness;
//    }
//
//    public void setEmployeeSickness(EmployeeSickness employeeSickness) {
//        EmployeeSickness oldEmployeeSickness = this.employeeSickness;
//        this.employeeSickness = employeeSickness;
//        changeSupport.firePropertyChange("employeeSickness", oldEmployeeSickness, employeeSickness);
//    }

    public Collection<Badge> getBadges() {
        return badges;
    }

    public void setBadges(Collection<Badge> badges) {
        Collection<Badge> oldBadges = this.badges;
        this.badges = badges;
        changeSupport.firePropertyChange("badges", oldBadges, badges);
    }

    public Collection<Event> getEventsLogCollection() {
        return eventsLogCollection;
    }

    public void setEventsLogCollection(Collection<Event> eventsLogCollection) {
        Collection<Event> oldEventsLogCollection = this.eventsLogCollection;
        this.eventsLogCollection = eventsLogCollection;
        changeSupport.firePropertyChange("eventsLogCollection", oldEventsLogCollection, eventsLogCollection);
    }

    public Collection<Event> getEventsLogCollection1() {
        return eventsLogCollection1;
    }

    public void setEventsLogCollection1(Collection<Event> eventsLogCollection1) {
        Collection<Event> oldEventsLogCollection1 = this.eventsLogCollection1;
        this.eventsLogCollection1 = eventsLogCollection1;
        changeSupport.firePropertyChange("eventsLogCollection1", oldEventsLogCollection1, eventsLogCollection1);
    }

    public EmployeeStatus getStatus() {
        return status;
    }

    public void setStatus(EmployeeStatus status) {
        EmployeeStatus oldStatus = this.status;
        this.status = status;
        changeSupport.firePropertyChange("status", oldStatus, status);
    }

    public void setFriendlyName(String name) {
        changeSupport.firePropertyChange("friendlyName", "oldValue", getFriendlyName());
    }

    public String getFriendlyName() {
        return surname + ", " + forename + " (" + employeeId + ")";
    }
    
    public AuthorisationLevel getAuthorisationLevel() {
        return authorisationLevel;
    }

    public void setAuthorisationLevel(AuthorisationLevel authorisationLevel) {
        AuthorisationLevel oldAuthorisationLevel = this.authorisationLevel;
        this.authorisationLevel = authorisationLevel;
        changeSupport.firePropertyChange("authorisationLevel", oldAuthorisationLevel, authorisationLevel);
    }

    public List<WorkingPattern> getWorkingPatterns() {
        return workingPatterns;
    }

    public void setWorkingPatterns(List<WorkingPattern> workingPatterns) {
        Collection<WorkingPattern> oldWorkingPatterns = this.workingPatterns;
        this.workingPatterns = workingPatterns;
        changeSupport.firePropertyChange("workingPatterns", oldWorkingPatterns, workingPatterns);
    }

    public Collection<HolidayRequest> getHolidayRequests() {
        return holidayRequests;
    }

    public void setHolidayRequests(Collection<HolidayRequest> holidayRequests) {
        Collection<HolidayRequest> oldHolidayRequests = this.holidayRequests;
        this.holidayRequests = holidayRequests;
        changeSupport.firePropertyChange("holidayRequests", oldHolidayRequests, holidayRequests);
    }

    public Collection<HolidayAdjustment> getHolidayAdjustments() {
        return holidayAdjustments;
    }

    public void setHolidayAdjustments(Collection<HolidayAdjustment> holidayAdjustments) {
        Collection<HolidayAdjustment> oldHolidayAdjustments = this.holidayAdjustments;
        this.holidayAdjustments = holidayAdjustments;
        changeSupport.firePropertyChange("holidayAdjustments", oldHolidayAdjustments, holidayAdjustments);
    }

    public Collection<SicknessReport> getSicknessReports() {
        return sicknessReports;
    }

    public void setSicknessReports(Collection<SicknessReport> sicknessReports) {
        Collection<SicknessReport> oldSicknessReports = this.sicknessReports;
        this.sicknessReports = sicknessReports;
        changeSupport.firePropertyChange("sicknessReports", oldSicknessReports, sicknessReports);
    }

    public Collection<WeeklyTime> getWeeklyTimes() {
        return weeklyTimes;
    }

    public void setWeeklyTimes(Collection<WeeklyTime> weeklyTimes) {
        Collection<WeeklyTime> oldWeeklyTimes = this.weeklyTimes;
        this.weeklyTimes = weeklyTimes;
        changeSupport.firePropertyChange("weeklyTimes", oldWeeklyTimes, weeklyTimes);
    }

    public Collection<MonthlyTime> getMonthlyTimes() {
        return monthlyTimes;
    }

    public void setMonthlyTimes(Collection<MonthlyTime> monthlyTimes) {
        Collection<MonthlyTime> oldMonthlyTimes = this.monthlyTimes;
        this.monthlyTimes = monthlyTimes;
        changeSupport.firePropertyChange("monthlyTimes", oldMonthlyTimes, monthlyTimes);
    }

    public Collection<ClockedPeriod> getClockedPeriods() {
        return clockedPeriods;
    }

    public void setClockedPeriods(Collection<ClockedPeriod> clockedPeriods) {
        Collection<ClockedPeriod> oldClockedPeriods = this.clockedPeriods;
        this.clockedPeriods = clockedPeriods;
        changeSupport.firePropertyChange("clockedPeriods", oldClockedPeriods, clockedPeriods);
    }

    public Collection<Session> getSessions() {
        return sessions;
    }

    public void setSessionsCollection(Collection<Session> sessions) {
        Collection<Session> oldSessions = this.sessions;
        this.sessions = sessions;
        changeSupport.firePropertyChange("sessions", oldSessions, sessions);
    }

    @Override
    public int hashCode() {
        int hash = 0;
        hash += (employeeId != null ? employeeId.hashCode() : 0);
        return hash;
    }

    @Override
    public boolean equals(Object object) {
        // TODO: Warning - this method won't work in the case the id fields are not set
        if (!(object instanceof Employee)) {
            return false;
        }
        Employee other = (Employee) object;
        if ((this.employeeId == null && other.employeeId != null) || (this.employeeId != null && !this.employeeId.equals(other.employeeId))) {
            return false;
        }
        return true;
    }

    @Override
    public String toString() {
        return getFriendlyName();
    }

    public void addPropertyChangeListener(PropertyChangeListener listener) {
        changeSupport.addPropertyChangeListener(listener);
    }

    public void removePropertyChangeListener(PropertyChangeListener listener) {
        changeSupport.removePropertyChangeListener(listener);
    }

    public static Query getEmployeesQuery(EntityManager entityManager) {
        return entityManager.createNamedQuery("Employee.findAll");
    }

    public static Query getActiveEmployeesQuery(EntityManager entityManager) {
        return entityManager.createNamedQuery("Employee.findByNotAuthorisationLevel").
                setParameter("authorisationLevel", AuthorisationLevel.DELETED);
    }

    public static Query getSupervisorsQuery(EntityManager entityManager) {
        return entityManager.createNamedQuery("Employee.findByAuthorisationLevel").
                setParameter("authorisationLevel", AuthorisationLevel.SUPERVISOR);
    }

    public static List<Employee> getEmployees(EntityManager entityManager) {
        return getEmployeesQuery(entityManager).getResultList();
    }

    public static List<Employee> getActiveEmployees(EntityManager entityManager) {
        return getActiveEmployeesQuery(entityManager).getResultList();
    }

    public static List<Employee> getSupervisors(EntityManager entityManager) {
        return getSupervisorsQuery(entityManager).getResultList();
    }

    public static List<Employee> getEmployeesByUsername(
            EntityManager entityManager, String username) {

        return entityManager.createNamedQuery("Employee.findByUsername").
                setParameter("username", username).
                getResultList();
    }
}